﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AAA.Meta.Quote.Data;
using AAA.Meta.Quote;
using AAA.Base.Util;

namespace AAA.Quote
{
    public class DataSummary
    {
        private List<TickData> _lstTickData;
        private List<BarRecord> _lstMinute;
        private List<BarRecord> _lstDay;
        private List<BarRecord> _lstWeek;
        private List<BarRecord> _lstMonth;
        private List<BarRecord> _lstYear;

        private string _strSessionStartTime;
        public string SessionStartTime
        {
          get { return _strSessionStartTime; }
          set { _strSessionStartTime = value; }
        }

        private string _strSessionEndTime;
        public string SessionEndTime
        {
          get { return _strSessionEndTime; }
          set { _strSessionEndTime = value; }
        }

        private void ResetData()
        {
            _lstMinute = null;
            _lstDay = null;
            _lstWeek = null;
            _lstMonth = null;
            _lstYear = null;
        }

        public void SetTickData(List<TickData> lstTickData)
        {
            _lstTickData = lstTickData;
            ResetData();
        }

        public void SetMinuteData(List<BarRecord> lstMinute)
        {
            ResetData();
            _lstMinute = lstMinute;
        }

        public void SetDayData(List<BarRecord> lstDay)
        {
            ResetData();
            _lstDay = lstDay;           
        }

        public void SetWeekData(List<BarRecord> lstWeek)
        {
            ResetData();
            _lstWeek = lstWeek;            
        }

        public void SetMonthData(List<BarRecord> lstMonth)
        {
            ResetData();
            _lstMonth = lstMonth;            
        }

        public void SetYearData(List<BarRecord> lstYear)
        {
            ResetData();
            _lstYear = lstYear;            
        }

        private BarRecord CreateBarRecord(BarCompressionEnum compression, int iInterval)
        {
            BarRecord barRecord = new BarRecord();

            barRecord.BarCompression = compression;
            barRecord.CompressionInterval = iInterval;
            barRecord["Volume"] = 0;
            barRecord["Amount"] = 0;
            return barRecord;
        }

        private void InitBarRecord(BarRecord sourceBar, BarRecord targetBar)
        {
            targetBar["Open"] = sourceBar["Open"];
            targetBar["High"] = sourceBar["High"];
            targetBar["Low"] = sourceBar["Low"];
            targetBar["Close"] = sourceBar["Close"];
            targetBar.BarDateTime = sourceBar.BarDateTime;
        }

        private void FillBarRecord(BarRecord sourceBar, BarRecord targetBar)
        {            
            targetBar["High"] = Math.Max(sourceBar["High"], targetBar["High"]);
            targetBar["Low"] = Math.Min(sourceBar["Low"], targetBar["Low"]);
            targetBar["Close"] = sourceBar["Close"];
            targetBar["Volume"] += sourceBar["Volume"];
            targetBar["Amount"] += float.IsNaN(sourceBar["Amount"]) ? 0 : sourceBar["Amount"];
        }

        public List<BarRecord> ToDailyData()
        {
            List<BarRecord> lstDay = new List<BarRecord>();
            BarRecord barRecord = null;

            if (_lstMinute == null)
                ToMinuteData();

            if (_lstMinute.Count == 0)
                return lstDay;

            barRecord = CreateBarRecord(BarCompressionEnum.Daily, 1);
            barRecord.BarDateTime = DateTime.Parse(_lstMinute[0].BarDateTime.ToString("yyyy/MM/dd") + " " + SessionStartTime);
            InitBarRecord(_lstMinute[0], barRecord);

            for(int i = 1; i < _lstMinute.Count; i++)
            {
                if (barRecord.BarDateTime.ToString("yyyy/MM/dd") != _lstMinute[i].BarDateTime.ToString("yyyy/MM/dd"))
                {
                    _lstDay.Add(barRecord);
                    barRecord = CreateBarRecord(BarCompressionEnum.Daily, 1);
                    barRecord.BarDateTime = DateTime.Parse(_lstMinute[i].BarDateTime.ToString("yyyy/MM/dd") + " " + SessionStartTime);
                    InitBarRecord(_lstMinute[i], barRecord);
                }

                FillBarRecord(_lstMinute[i], barRecord);
            }

            _lstDay.Add(barRecord);

            return lstDay;
        }

        public List<BarRecord> ToMinuteData()
        {
            _lstMinute = ToMinuteData(1);
            return _lstMinute;
        }

        public List<BarRecord> ToMinuteData(int iInterval)
        {
            if(_lstMinute == null)
                return GroupMinuteData(1);

            if ((iInterval == 1) || (_lstMinute.Count == 0))
                return _lstMinute;


            List<BarRecord> lstMinute = new List<BarRecord>();
            BarRecord barRecord = CreateBarRecord(BarCompressionEnum.Min, iInterval);            
            DateTime dtSessionStartTime = DateTime.Parse("1900/01/01 " + SessionStartTime);
            DateTime dtSessionEndTime = DateTime.Parse("1900/01/01 " + SessionEndTime);
            DateTime dtStarTime = dtSessionStartTime;

            for (int i = 0; i < _lstMinute.Count; i++)
            {
                if (_lstMinute[i].BarDateTime.ToString("yyyy/MM/dd") != barRecord.BarDateTime.ToString("yyyy/MM/dd"))
                {
                    dtStarTime = new DateTime(_lstMinute[i].BarDateTime.Year,
                                              _lstMinute[i].BarDateTime.Month,
                                              _lstMinute[i].BarDateTime.Day,
                                              dtSessionStartTime.Hour,
                                              dtSessionStartTime.Minute,
                                              dtSessionStartTime.Second).AddMinutes(1);
                    if (i != 0)
                    {
                        barRecord.BarDateTime = new DateTime(_lstMinute[i - 1].BarDateTime.Year,
                                                             _lstMinute[i - 1].BarDateTime.Month,
                                                             _lstMinute[i - 1].BarDateTime.Day,
                                                             dtSessionEndTime.Hour,
                                                             dtSessionEndTime.Minute,
                                                             dtSessionEndTime.Second);
                        lstMinute.Add(barRecord);
                    }
                    InitBarRecord(_lstMinute[i], barRecord);
                }

                if (((((int)DateTimeHelper.DateDiff(DateTimeHelper.MINUTE, _lstMinute[i].BarDateTime, dtStarTime)) % iInterval) == 0) &&
                    (_lstMinute[i].BarDateTime.CompareTo(dtStarTime) != 0))
                {                    
                    barRecord.BarDateTime = _lstMinute[i - 1].BarDateTime;
                    lstMinute.Add(barRecord);
                    barRecord = CreateBarRecord(BarCompressionEnum.Min, iInterval);
                    InitBarRecord(_lstMinute[i], barRecord);
                }
                FillBarRecord(_lstMinute[i], barRecord);
            }

            barRecord.BarDateTime = _lstMinute[_lstMinute.Count - 1].BarDateTime.AddMinutes(iInterval - (((int)DateTimeHelper.DateDiff(DateTimeHelper.MINUTE, _lstMinute[_lstMinute.Count - 1].BarDateTime, dtSessionStartTime)) % iInterval));
            lstMinute.Add(barRecord);

            return lstMinute;
            
        }

        private List<BarRecord> GroupMinuteData(int iInterval)
        {
            List<BarRecord> lstMinute = new List<BarRecord>();
            BarRecord barRecord = null;

            if (_lstTickData == null)
                return lstMinute;

            DateTime dtStartTime = DateTime.Parse("1900/01/01 " + SessionStartTime);
            DateTime dtEndTime = DateTime.Parse("1900/01/01 " + SessionEndTime);

            foreach (TickData tickData in _lstTickData)            
            {
                if (tickData.Date != dtStartTime.ToString("yyyy/MM/dd"))
                {
                    dtStartTime = DateTime.Parse(tickData.Date + " " + SessionStartTime);
                    dtEndTime = DateTime.Parse(tickData.Date + " " + SessionEndTime);

                    if (barRecord != null)
                        lstMinute.Add(barRecord);
                    barRecord = CreateBarRecord(BarCompressionEnum.Min, iInterval);
                    
                    barRecord.BarDateTime = dtStartTime.AddMinutes(iInterval);
                }

                while((tickData.Time.CompareTo(barRecord.BarDateTime.ToString("HH:mm:ss")) > 0) && (barRecord.BarDateTime <= dtEndTime))
                {
                    if (float.IsNaN(barRecord["Open"]) && lstMinute.Count > 0)
                    {
                        barRecord["Open"] = lstMinute[lstMinute.Count - 1]["Open"];
                        barRecord["High"] = lstMinute[lstMinute.Count - 1]["High"];
                        barRecord["Low"] = lstMinute[lstMinute.Count - 1]["Low"];
                        barRecord["Close"] = lstMinute[lstMinute.Count - 1]["Close"];
                        barRecord["Volume"] = 0;
                    }
                    lstMinute.Add(barRecord);
                    barRecord = CreateBarRecord(BarCompressionEnum.Min, iInterval); 
                    barRecord.BarDateTime = lstMinute[lstMinute.Count - 1].BarDateTime.AddMinutes(iInterval);                    
                }

                if (float.IsNaN(barRecord["Open"]))
                {
                    barRecord["Open"] = tickData.Price;
                    barRecord["High"] = tickData.Price;
                    barRecord["Low"] = tickData.Price;
                    barRecord["Close"] = tickData.Price;
                    barRecord["Volume"] = 0;
                    barRecord["Amount"] = 0;
                }

                barRecord["High"] = Math.Max(tickData.Price, barRecord["High"]);
                barRecord["Low"] = Math.Min(tickData.Price, barRecord["Low"]);
                barRecord["Close"] = tickData.Price;
                barRecord["Volume"] += tickData.Volume;
            }

            if (barRecord["Volume"] > 0)
                lstMinute.Add(barRecord);
            return lstMinute;
        }

    }
}
